﻿#include"C++.h"

//泛型编程：编写与类型无关的通用代码，是代码复用的一种手段。模板是泛型编程的基础

//函数模板:函数模板代表了一个函数家族，该函数模板与类型无关，在使用时被参数化，根据实参类型产生函数的特定类型版本

//函数模板格式：template<typename T1, typename T2,......,typename Tn>
//				返回值类型 函数名(参数列表) {}
//注意：typename是用来定义模板参数关键字，也可以使用class(切记：不能使用struct代替class)
//template<typename T>
//void Swap(T& left, T& right)
//{
//	T temp = left;
//	left = right;
//	right = temp;
//}


//函数模板的原理：函数模板是一个蓝图，它本身并不是函数，是编译器用使用方式产生特定具体类型函数的模具。
//				  所以其实模板就是将本来应该我们做的重复的事情交给了编译器
//在编译器编译阶段，对于模板函数的使用，编译器需要根据传入的实参类型来推演生成对应类型的函数以供调用


//函数模板的实例化：用不同类型的参数使用函数模板时，称为函数模板的实例化。模板参数实例化分为：隐式实例化和显式实例化
// 1. 隐式实例化：让编译器根据实参推演模板参数的实际类型
//template<class T>
//T Add(const T& left, const T& right)
//{
//	return left + right;
//}
//int main()
//{
//	int a1 = 10, a2 = 20;
//	double d1 = 10.1, d2 = 20.2;
//	Add(a1, a2);
//	Add(d1, d2);
//	/*
//	该语句不能通过编译，因为在编译期间，当编译器看到该实例化时，需要推演其实参类型通过实参a1将T推演为int，
//	通过实参d1将T推演为double类型，但模板参数列表中只有一个T，编译器无法确定此处到底该将T确定为int 或者 double类型而报错
//	注意：在模板中，编译器一般不会进行类型转换操作，因为一旦转化出问题，编译器就需要背黑锅
//	Add(a1, d1);
//	*/
//// 此时有两种处理方式：1. 用户自己来强制转化 2. 使用显式实例化
//	Add(a1, (int)d1);
//	return 0;
//}

//2. 显式实例化：在函数名后的<>中指定模板参数的实际类型
//int main(void)
//{
//	int a = 10;
//	double b = 20.2;
//	// 显式实例化
//	Add<int>(a, b);
//	return 0;
//}
//如果类型不匹配，编译器会尝试进行隐式类型转换，如果无法转换成功编译器将会报错


//模板参数的匹配原则
//1. 一个非模板函数可以和一个同名的函数模板同时存在，而且该函数模板还可以被实例化为这个非模板函数
// 专门处理int的加法函数
//int Add(int left, int right)
//{
//	return left + right;
//}
//// 通用加法函数
//template<class T>
//T Add(T left, T right)
//{
//	return left + right;
//}
//void Test()
//{
//	Add(1, 2); // 与非模板函数匹配，编译器不需要特化
//	Add<int>(1, 2); // 调用编译器特化的Add版本
//}

//2. 对于非模板函数和同名函数模板，如果其他条件都相同，在调动时会优先调用非模板函数而不会从该模板产生出一个实例。
//	 如果模板可以产生一个具有更好匹配的函数， 那么将选择模板
// 专门处理int的加法函数
//int Add(int left, int right)
//{
//	return left + right;
//}
//// 通用加法函数
//template<class T1, class T2>
//T1 Add(T1 left, T2 right)
//{
//	return left + right;
//}
//void Test()
//{
//	Add(1, 2); // 与非函数模板类型完全匹配，不需要函数模板实例化
//	Add(1, 2.0); // 模板函数可以生成更加匹配的版本，编译器根据实参生成更加匹配的Add函数
//}

//3. 模板函数不允许自动类型转换，但普通函数可以进行自动类型转换


//类模板的定义格式
//template<class T1, class T2, ..., class Tn>
//class 类模板名
//{
//	// 类内成员定义
//};

// 类模版
//template<typename T>
//class Stack
//{
//public:
//	Stack(size_t capacity = 4)
//	{
//		_array = new T[capacity];
//		_capacity = capacity;
//		_size = 0;
//	}
//	void Push(const T& data);
//private:
//	T* _array;
//	size_t _capacity;
//	size_t _size;
//};
// 模版不建议声明和定义分离到两个文件.h 和.cpp会出现链接错误，具体原因后面会讲
//template<class T>
//void Stack<T>::Push(const T& data)
//{
//	// 扩容
//	_array[_size] = data;
//	++_size;
//}
//int main()
//{
//	Stack<int> st1; // int
//	Stack<double> st2; // double
//	return 0;
//}

//类模板的实例化：类模板实例化与函数模板实例化不同，类模板实例化需要在类模板名字后跟<>，然后将实例化的
//				  类型放在<>中即可，类模板名字不是真正的类，而实例化的结果才是真正的类。
// Stack是类名，Stack<int>才是类型
//Stack<int> st1; // int
//Stack<double> st2; // double


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 模板
//模板参数分类类型形参与非类型形参。
// 类型形参即：出现在模板参数列表中，跟在class或者typename之类的参数类型名称。
// 非类型形参，就是用一个常量作为类(函数)模板的一个参数，在类(函数)模板中可将该参数当成常量来使用。
//注意：
//1. 浮点数、类对象以及字符串是不允许作为非类型模板参数的。
//2. 非类型的模板参数必须在编译期就能确认结果。


////#define N 10
//template<size_t N = 10, bool flag = false>
//class Stack
//{
//private:
//	int _a[N];
//	int _top;
//};

// C++20
//template<double D>
//class A
//{
//private:
//
//};

//int main()
//{
//	Stack<> s0;
//	Stack<5> s1;
//	Stack<10> s2;
//
//	return 0;
//}


//template<class T, size_t N = 10>
//class array
//{
//public:
//	T& operator[](size_t index)
//	{ 
//		assert(index < N);
//		return _array[index]; 
//	}
//private:
//	T _array[N];
//	size_t _size;
//};

//int main()
//{
//	//栈
//	array <int, 10> a1;
//	array<int, 100>a2;
//
//	int a3[10];
//
//	// 越界检查的问题
//	// 静态数组 抽查
//	// 越界读不检查，越界写抽查
//	cout << a3[10] << endl;
//	//a3[10] = 10;
//	//a3[11] = 11;
//	//a3[12] = 12;
//	//a3[20] = 20;
//
//	// array 越界读写都可检查
//	//a1[10];
//	//a1[11] = 11;
//
//	// 堆
//	vector<int> v(10, 1);
//	cout << sizeof(a1) << endl;
//	cout << sizeof(v) << endl;
//
//	return 0;
//}


//void func()
//{
//	int a = 1;
//	cout << &a << endl; 
//
//}
//
//int main()
//{
//	int a = 0;
//	cout << &a << endl;
//
//	func();
//
//	return 0;
//}


// 模板的特化 - 通常情况下，使用模板可以实现一些与类型无关的代码，但对于一些特殊类型的可能会得到一些错误的结果，需要特殊处理
//函数模板的特化步骤：
//1. 必须要先有一个基础的函数模板
//2. 关键字template后面接一对空的尖括号 < >
//3. 函数名后跟一对尖括号，尖括号中指定需要特化的类型
//4. 函数形参表: 必须要和模板函数的基础参数类型完全相同，如果不同编译器可能会报一些奇怪的错误。
// 
// 函数模板 -- 参数匹配
//template<class T>
//bool Lessfunc(const T& left, const T& right)
//{
//	return left < right;
//}

// 对Less函数模板进行特化
//template<>
//bool Lessfunc<const Date*>(const Date* const& left,const  Date* const& right)
//{
//	return *left < *right;
//}
//template<>
//bool Lessfunc< Date*>( Date* const& left,   Date* const& right)
//{
//	return *left < *right;
//}

//bool Lessfunc(const Date* left,const Date* right)
//{
//	return *left < *right;
//}
//bool Lessfunc( Date* left,  Date* right)
//{
//	return *left < *right;
//}

//int main()
//{
//	cout << Lessfunc(1, 2) << endl;
//
//	Date d1(2022, 7, 7);
//	Date d2(2022, 7, 8);
//	cout << Lessfunc(d1, d2) << endl; // 可以比较，结果正确
//
//	Date* p1 = &d1;
//	Date* p2 = &d2;
//	cout << Lessfunc(p1, p2) << endl; // 可以比较，结果错误
//
//	const Date* p3 = &d1;
//	const Date* p4 = &d2;
//	cout << Lessfunc(p3, p4) << endl; // 可以比较，结果错误
//
//	return 0;
//}


//template<class T1, class T2>
//class Data
//{
//public:
//	Data() { cout << "Data<T1, T2>" << endl; }
//private:
//	T1 _d1;
//	T2 _d2;
//};
//
//// 全特化
//template<>
//class Data<int, char>
//{
//public:
//	Data() { cout << "Data<int, char>" << endl; }
//};
//
//// 半/偏特化
//template<class T1>
//class Data<T1, double>
//{
//public:
//	Data() { cout << "Data<T1, double>" << endl; }
//};
//
//template<class T1>
//class Data<T1, char>
//{
//public:
//	Data() { cout << "Data<T1, char>" << endl; }
//};
//
//// 偏特化，传的类型是指针
//template <typename T1, typename T2>
//class Data <T1*, T2*>
//{
//public:
//	Data()
//	{
//		cout << "Data<T1*, T2*>" << endl;
//	}
//};
//
//template <typename T1, typename T2>
//class Data <T1&, T2&>
//{
//public:
//	Data()
//	{
//		cout << "Data<T1&, T2&>" << endl;
//	}
//};
//
//template <typename T1, typename T2>
//class Data <T1&, T2*>
//{
//public:
//	Data()
//	{
//		cout << "Data<T1&, T2*>" << endl;
//
//		int a = 0;
//		T1& x = a;
//		T2* y = &a;
//		T1 z = a;
//
//		cout << typeid(x).name() << endl;
//		cout << typeid(y).name() << endl;
//	}
//
//	void Push(const T1& x)
//	{}
//};
//
//int main()
//{
//	Data<int, int>d1;
//	Data<int, char>d2;
//	Data<int, double>d3;
//	Data<char, double>d4;
//	Data<char, char>d5;
//
//	Data<char*, char*>d6;
//	Data<int*, char*>d7;
//	Data<int&, char&> d8;
//	Data<int&, double&> d9;
//	Data<int&, int*> d10;
//
//	return 0;
//}


//#include"模板.h"
//
////template<class T>
////T Add(const T& left, const T& right)
////{
////	return left + right;
////}
//
//void func(const int& left, const int& right)
//{
//	
//	cout << "void func(const int& left, const int& right);" << endl;
//}

// 显示实例化
//template
//int Add(const int& left, const int& right);
